package com.xiaoshuidi.cloud.module.iot.service.impl.thirdPartImpl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xiaoshuidi.cloud.framework.tenant.core.aop.TenantIgnore;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.WaterMeterCommonResponseModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.OperateThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.PullThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenResponseModel;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbDeviceDo;
import com.xiaoshuidi.cloud.module.iot.dal.repository.DeviceRepository;
import com.xiaoshuidi.cloud.module.iot.enums.BrandEnum;
import com.xiaoshuidi.cloud.module.iot.enums.DeviceTypeEnum;
import com.xiaoshuidi.cloud.module.iot.service.AllAbstractThirdInstanceService;
import com.xiaoshuidi.cloud.module.iot.service.CacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 埃美柯水表
 */
@Service("emecoInstanceServiceImpl")
public class EmecoInstanceServiceImpl extends AllAbstractThirdInstanceService {

    private final static Logger LOGGER = LoggerFactory.getLogger(EmecoInstanceServiceImpl.class);

    @Value("${emeco.callback:https://9fde-43-239-85-132.ngrok-free.app/callback/emeco/cb}")
    private String callback;

    @Value("${emeco.getAccessToken.url:https://oss-v4-test-open.elecwatt.com:8043/open/api/v3/oauth2/token}")
    private String getAccessTokenUrl;

    @Value("${emeco.refreshAccessToken.rul:https://oss-v4-test-open.elecwatt.com:8043/open/api/v3/oauth2/refresh}")
    private String refreshAccessTokenUrl;

    @Value("${emeco.deviceList.url:https://oss-v4-test-open.elecwatt.com:8043/oss-admin/api/v3/device/new-query}")
    private String deviceListUrl;

    @Value("${emeco.callInfo.url:https://oss-v4-test-open.elecwatt.com:8043/open/iot2/call/info/async}")
    private String callInfoUrl;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private DeviceRepository deviceDataAccess;
    

    @Override
    public String getBrand() {
        return BrandEnum.EMECO.getBrand();
    }

    @Override
    public AccessTokenResponseModel getAccessToken(AccessTokenRequestModel accessTokenRequestModel) throws Exception {
        String appId = accessTokenRequestModel.getAppId();
        String appKey = accessTokenRequestModel.getAppKey();
        AccessTokenResponseModel accessTokenResponseModel = new AccessTokenResponseModel();
        //1首先获取缓存里面是否存在accessToken
        String accessToken = cacheService.getString("emeco:accessToken");
        if(StrUtil.isBlank(accessToken)){
            //获取refreshToken是否存在
            String refreshToken = cacheService.getString("emeco:refreshToken");
            if(StrUtil.isBlank(refreshToken)){
                //refreshToken也不存在的直接调用接口重新获取
                String result = HttpRequest.post(getAccessTokenUrl)
                        .form("client_id",appId)
                        .form("client_secret",appKey).execute().body();
                return dealToken(result);
            }else{
                //refreshToken存在直接调用刷新接口获取新的accessToken
                String result = HttpRequest.post(refreshAccessTokenUrl).form("client_id", appId)
                        .form("client_secret", appKey)
                        .form("refresh_token", refreshToken).execute().body();
                return dealToken(result);
            }
        }
        accessTokenResponseModel.setAccessToken(accessToken);
        return accessTokenResponseModel;
    }

    /**
     * 统一的token缓存保存以及返回数据
     *
     * @param result
     * @throws Exception
     */
    private AccessTokenResponseModel dealToken(String result) throws Exception {
        AccessTokenResponseModel accessTokenResponseModel = new AccessTokenResponseModel();
        if (StrUtil.isNotBlank(result)) {
            JSONObject resultJson = JSONObject.parseObject(result);
            String code = resultJson.getString("code");
            if ("ok".equals(code)) {
                JSONObject resultJsonJSONObject = resultJson.getJSONObject("result");
                if (resultJsonJSONObject != null) {
                    String accessToken = resultJsonJSONObject.getString("access_token");
                    String refreshToken = resultJsonJSONObject.getString("refresh_token");
                    int expiresIn = resultJsonJSONObject.getIntValue("expires_in");
                    int refreshExpiresIn = resultJsonJSONObject.getIntValue("refresh_expires_in");
                    if (expiresIn > 0) {
                        accessTokenResponseModel.setAccessToken(accessToken);
                        accessTokenResponseModel.setExpireTime(expiresIn);
                        //将该token保存到redis,缓存失败比第三方少一分钟。避免第三方token失效了还保存旧的token
                        cacheService.putString("emeco:accessToken", accessToken, expiresIn-60);
                        cacheService.putString("emeco:refreshToken", refreshToken, refreshExpiresIn-60);
                    }

                }
            }
        }
        return accessTokenResponseModel;
    }

    @Override
    @TenantIgnore
    public List<TbDeviceDo> getDevice(PullThirdDeviceRequestModel pullThirdDeviceRequestModel) throws Exception {
        List<TbDeviceDo> tbDeviceDos = new ArrayList<>();
        JSONObject params = new JSONObject();
        int pageSize=20;
        int pageNumb = 1;
        int size=0;
        String apiNo = pullThirdDeviceRequestModel.getTbAccountDo().getApiNo();
        String accessToken = pullThirdDeviceRequestModel.getAccessToken();
        List<TbDeviceDo> existDevices = deviceDataAccess.getDeviceListByOneApiNo(apiNo);
        List<String> existDevicesUuid = existDevices.stream().map(TbDeviceDo::getDeviceThirdNo).collect(Collectors.toList());
        do {
            size = 0;
            params.put("type", "WATER_METER");
            params.put("pageNumb", pageNumb);
            params.put("pageSize", pageSize);
            String result = HttpRequest.post(deviceListUrl).body(JSONObject.toJSONString(params))
                    .header("auth-token",accessToken).execute().body();
            JSONObject resultJson = JSONObject.parseObject(result);
            if (resultJson != null) {
                String code = resultJson.getString("code");
                if ("ok".equals(code)) {
                    JSONObject resultJsonJSONObject = resultJson.getJSONObject("result");
                    if (resultJsonJSONObject != null) {
                        size = resultJsonJSONObject.getIntValue("total");
                        JSONArray datas = resultJsonJSONObject.getJSONArray("data");
                        JSONArray finalDatas = datas;
                        datas = new JSONArray(IntStream.range(0, datas.size()).filter(i -> !existDevicesUuid.contains(finalDatas.getJSONObject(i).getString("uuid"))).mapToObj(datas::getJSONObject).collect(Collectors.toList()));
                        for (int i = 0; i < datas.size(); i++) {
                            JSONObject data = datas.getJSONObject(i);
                            TbDeviceDo tbDeviceDo = new TbDeviceDo();
                            String mac = data.getString("mac");
                            //特殊处理，mac作为设备号
                            tbDeviceDo.setDeviceThirdNo(mac);
                            tbDeviceDo.setDeviceName(data.getString("mpName"));
                            tbDeviceDo.setDeviceModel(data.getString("type"));
                            tbDeviceDo.setReportTime(LocalDateTime.now());
                            Boolean online = data.getBoolean("online");
                            tbDeviceDo.setOnlineStatus(online? 1 : 0);
                            tbDeviceDo.setCurrentReading(0D);//第一次默认为0.因为厂商不返回该数据
                            tbDeviceDo.setDeviceType(DeviceTypeEnum.COLD_WATERMETE_TYPE_ENUM.getCode());
                            tbDeviceDo.setApiNo(apiNo);
                            tbDeviceDos.add(tbDeviceDo);
                        }
                    }
                }
            }
            pageNumb = pageNumb + 1;
        } while (size >= 20);
        return tbDeviceDos;
    }

    @Override
    public WaterMeterCommonResponseModel refreshWatermeterInfo(WaterMeterCommonResponseModel waterMeterCommonResponseModel, OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        waterMeterCommonResponseModel.setOperateResult(false);
        String accessToken = operateThirdDeviceRequestModel.getAccessToken();
        String deviceThirdNo = operateThirdDeviceRequestModel.getDeviceThirdNo();
        JSONObject params = new JSONObject();
        params.put("type", "WATER_METER");
        params.put("mac",deviceThirdNo);
        String result = HttpRequest.post(deviceListUrl)
                .header("auth-token",accessToken).body(JSONObject.toJSONString(params)).execute().body();
        if(StrUtil.isNotBlank(result)){
            JSONObject resultJson = JSONObject.parseObject(result);
            String code = resultJson.getString("code");
            if("ok".equals(code)) {
                JSONObject resultJsonJSONObject = resultJson.getJSONObject("result");
                if (Objects.nonNull(resultJsonJSONObject)) {
                    JSONArray datas = resultJsonJSONObject.getJSONArray("data");
                    if(Objects.nonNull(datas)&&!datas.isEmpty()){
                        JSONObject data = datas.getJSONObject(0);
                        if (data != null) {
                            String mac = data.getString("mac");
                            String spaceId = data.getString("spaceId");
                            if(NumberUtil.isNumber(spaceId)){
                                waterMeterCommonResponseModel.setRoomId(Long.parseLong(spaceId));
                            }
                            Boolean online = data.getBoolean("online");
                            waterMeterCommonResponseModel.setOnlineStatus(online? 1 : 0);
                            waterMeterCommonResponseModel.setPowerStatus(1);//默认的电源状态为1
                            //请求第三方接口，通知第三方接口返回实时读数
                            //由于该厂商不返回水表读书需要异步调用，也就是需要调用接口，等待厂商回调本服务接口
                            Boolean asyncResult = asyncCallInfo(mac, callback, accessToken);
                            waterMeterCommonResponseModel.setOperateResult(asyncResult);
                        }
                    }
                }
            }
        }
        return waterMeterCommonResponseModel;
    }

    public Boolean asyncCallInfo(String mac,String callback,String accessToken) throws Exception {
        JSONObject params = new JSONObject();
        params.put("sn", mac);
        params.put("callback", callback);
        params.put("dataType", "CALLING_FLOW_DATA");
        String result = HttpRequest.post(callInfoUrl).body(JSONObject.toJSONString(params)).header("auth-token", accessToken).execute().body();
        if(StrUtil.isNotBlank(result)){
            LOGGER.info("埃美柯-请求水表(异步)召测设备信息返回结果:{}",result);
            JSONObject resultJson = JSONObject.parseObject(result);
            if (resultJson != null) {
                Boolean success = resultJson.getBoolean("success");
                if(!success){
                    LOGGER.info("埃美柯-请求水表(异步)召测设备信息返回结果失败:{}",mac);
                }
                return success;
            }
        }
        return Boolean.FALSE;
    }
}
